import mailbox, urllib2
from urlparse import urlparse
from mailmigration import errors

class _networkMailbox(mailbox.Mailbox):
    """A mailbox accessed over the network (HTTP, IMAP, etc).""" 

    def __init__(self, url, factory=None, create=False, *args, **kwargs):
        """Initialize a _networkMailbox instance.
            (We do not send on the init method to the Mailbox base class)
        """
        self._url = urlparse(url)
        self._factory = factory
        #build_opener adds several handlers by default, but provides a quick way
        #to add more and/or override the default handlers.
        self._opener = urllib2.build_opener(*args)
        self._request = urllib2.Request(url, **kwargs)
        self._response = None

    def add(self, message):
        """Network mailboxes are read-only be default."""
        raise errors.ReadOnlyMailboxError('%s mailboxes are read-only by default.' % self.__class__.__name__)

    def remove(self, key):
        """Network mailboxes are read-only be default."""
        raise errors.ReadOnlyMailboxError('%s mailboxes are read-only by default.' % self.__class__.__name__)

    def __setitem__(self, key, message):
        """Network mailboxes are read-only be default."""
        raise errors.ReadOnlyMailboxError('%s mailboxes are read-only by default.' % self.__class__.__name__)

    def get_message(self, key):
        """Return a Message representation or raise a KeyError."""
        raise NotImplementedError('Method must be implemented by subclass')

    def get_string(self, key):
        """Return a string representation or raise a KeyError."""
        raise NotImplementedError('Method must be implemented by subclass')

    def get_file(self, key):
        """Return a file-like representation or raise a KeyError."""
        raise NotImplementedError('Method must be implemented by subclass')

    def iterkeys(self):
        """Return an iterator over keys."""
        raise NotImplementedError('Method must be implemented by subclass')

    def has_key(self, key):
        """Return True if the keyed message exists, False otherwise."""
        raise NotImplementedError('Method must be implemented by subclass')

    def __len__(self):
        """Return a count of messages in the mailbox."""
        raise NotImplementedError('Method must be implemented by subclass')

    def flush(self):
        """Network mailboxes are read-only be default."""
        raise errors.ReadOnlyMailboxError('%s mailboxes are read-only by default.' % self.__class__.__name__)

    def lock(self):
        """Network mailboxes are read-only be default."""
        raise errors.ReadOnlyMailboxError('%s mailboxes are read-only by default.' % self.__class__.__name__)

    def unlock(self):
        """Network mailboxes are read-only be default."""
        raise errors.ReadOnlyMailboxError('%s mailboxes are read-only by default.' % self.__class__.__name__)

    def close(self):
        """Flush and close the mailbox."""
        raise NotImplementedError('Method must be implemented by subclass')

    def _refresh(self):
        """Perform network request for data."""
        raise NotImplementedError('Method must be implemented by subclass')

class _httpMailbox(_networkMailbox):
    """A mailbox accessed over HTTP.""" 

    def __init__(self, url, factory=None, create=False,
                 user_agent='Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
                 *args, **kwargs):
        """Initialize a _networkMailbox instance.
            (We do not send on the init method to the Mailbox base class)
        """
        if create:
            raise errors.ReadOnlyMailboxError('%s mailboxes are read-only.' % self.__class__.__name__)
        _networkMailbox.__init__(self, url, factory, create, *args, **kwargs)
        self._user_agent = user_agent
        self._request.add_header('User-Agent', self._user_agent)

    def _refresh(self):
        """Perform http request for data.
            Note: we don't issue a read() against the response initially.
            If you need to be able to seek/tell, you should wrap self._file.read()
            in a call to StringIO.
        """
        #self._toc = {}
        #The except HTTPError must come first, otherwise except URLError
        #will also catch an HTTPError.
        try:
            self._response = self._opener.open(self._request)
            self._file = self._response
        except urllib2.HTTPError, e:
            raise mailbox.NoSuchMailboxError('HTTP Error %d: %s' % (e.code, "The server couldn't fulfill the request."))
        except urllib2.URLError, e:
            raise mailbox.NoSuchMailboxError('Failed to contact server: %s' % e.reason)

class _ftpMailbox(_networkMailbox):
    """A mailbox accessed over FTP.""" 

    def _refresh(self):
        """Perform ftp request for data.
            Note: we don't issue a read() against the response initially.
            If you need to be able to seek/tell, you should wrap self._file.read()
            in a call to StringIO.
        """
        #self._toc = {}
        #The except FTPError must come first, otherwise except URLError
        #will also catch an FTPError.
        try:
            self._response = self._opener.open(self._request)
            self._file = self._response
        except urllib2.FTPError, e:
            raise mailbox.NoSuchMailboxError('FTP Error %d: %s' % (e.code, "The server couldn't fulfill the request."))
        except urllib2.URLError, e:
            raise mailbox.NoSuchMailboxError('Failed to contact server: %s' % e.reason)
